<template>
    <canvas class="app-sign-canvas" :id="domId">
        您的浏览器不支持canvas技术,请升级浏览器!
    </canvas>
</template>
<script>
    export default {
        name: 'SignCanvas',
        model: {
            value: 'image',
            event: 'confirm'
        },
        props: {
            image: {
                required: false,
                type: [String],
                default: null
            },
            options: {  //配置项
                required: false,
                type: [Object],
                default: () => null
            },
        },
        data () {
            return {
                value: null, //base64
                domId: `sign-canvas-${Math.random().toString(36).substr(2)}`,  //生成唯一dom标识
                canvas:null,    //canvas dom对象
                context:null,   //canvas 画布对象
                config: {
                    lastWriteSpeed: 1,  //书写速度 [Number] 可选
                    lastWriteWidth: 2,  //下笔的宽度 [Number] 可选
                    lineCap: 'round',   //线条的边缘类型 [butt]平直的边缘 [round]圆形线帽 [square]	正方形线帽
                    lineJoin: 'round',  //线条交汇时边角的类型  [bevel]创建斜角 [round]创建圆角 [miter]创建尖角。
                    canvasWidth: 600, //canvas宽高 [Number] 可选
                    canvasHeight: 600,  //高度  [Number] 可选
                    isShowBorder: true, //是否显示边框 [可选]
                    bgColor: '#fcc', //背景色 [String] 可选
                    borderWidth: 1, // 网格线宽度  [Number] 可选
                    borderColor: "#ff787f", //网格颜色  [String] 可选
                    writeWidth: 5, //基础轨迹宽度  [Number] 可选
                    maxWriteWidth: 30, // 写字模式最大线宽  [Number] 可选
                    minWriteWidth: 5, // 写字模式最小线宽  [Number] 可选
                    writeColor: '#101010', // 轨迹颜色  [String] 可选
                    isSign: false, //签名模式 [Boolean] 默认为非签名模式,有线框, 当设置为true的时候没有任何线框
                    imgType:'png'   //下载的图片格式  [String] 可选为 jpeg  canvas本是透明背景的
                }
            };
        },
        mounted () {
            this.init();
        },
        methods: {
            init () {
                this.canvas = document.getElementById(this.domId);
                this.context = this.canvas.getContext("2d");
                const options = this.options;
                if (options) {
                    for (const key in options) {
                        this.config[key] = options[key];
                    }
                }
                this.canvasInit();
                this.canvasClear();
            },
            draw(value){
                // console.log(value)
                if(value){
                    if(value.indexOf("[img]") === 0){
                        value = value.substring("[img]".length)
                        if(value.indexOf("http") !== 0){
                            value = `${API}${value}`
                        }
                    }
                    const img = new Image();
                    img.src = value
                    img.setAttribute("crossOrigin",'Anonymous')
                    img.onload = () => {
                        this.context.drawImage(img, 0, 0, this.config.canvasWidth, this.config.canvasHeight)
                    }
                    // console.log(img)
                    // this.context.
                }
            },
            /**
             * 轨迹宽度
             */
            setLineWidth () {
                const nowTime = new Date().getTime();
                const diffTime = nowTime - this.config.lastWriteTime;
                this.config.lastWriteTime = nowTime;
                let returnNum = this.config.minWriteWidth + (this.config.maxWriteWidth - this.config.minWriteWidth) * diffTime / 30;
                if (returnNum < this.config.minWriteWidth) {
                    returnNum = this.config.minWriteWidth;
                } else if (returnNum > this.config.maxWriteWidth) {
                    returnNum = this.config.maxWriteWidth;
                }
                returnNum = returnNum.toFixed(2);
                //写字模式和签名模式
                if (this.config.isSign) {
                    this.context.lineWidth = this.config.writeWidth;
                } else {
                    this.context.lineWidth = this.config.lastWriteWidth = this.config.lastWriteWidth / 4 * 3 + returnNum / 4;
                }
            },
            /**
             * 绘制轨迹
             */
            writing (point) {
                this.context.beginPath();
                this.context.moveTo(this.config.lastPoint.x, this.config.lastPoint.y);
                this.context.lineTo(point.x, point.y);
                this.setLineWidth();
                this.context.stroke();
                this.config.lastPoint = point;
                this.context.closePath();
            },
            /**
             * 轨迹样式
             */
            writeContextStyle () {
                this.context.beginPath();
                this.context.strokeStyle = this.config.writeColor;
                this.context.lineCap = this.config.lineCap;
                this.context.lineJoin = this.config.lineJoin;
            },
            /**
             * 写开始
             */
            writeBegin (point) {
                this.config.isWrite = true;
                this.config.lastWriteTime = new Date().getTime();
                this.config.lastPoint = point;
                this.writeContextStyle();
            },
            /**
             * 写结束
             */
            writeEnd (point) {
                this.config.isWrite = false;
                this.config.lastPoint = point;
                this.saveAsImg();
            },
            /**
             * 清空画板
             */
            canvasClear () {
                this.context.save();
                this.context.strokeStyle = this.config.writeColor;
                this.context.clearRect(0, 0, this.config.canvasWidth, this.config.canvasHeight);
                this.context.beginPath();
                let size = this.config.borderWidth / 2;
                if(this.config.isShowBorder){
                    //画外面的框
                    this.context.moveTo(size, size);
                    this.context.lineTo(this.config.canvasWidth - size, size);
                    this.context.lineTo(this.config.canvasWidth - size, this.config.canvasHeight - size);
                    this.context.lineTo(size, this.config.canvasHeight - size);
                    this.context.closePath();
                    this.context.lineWidth = this.config.borderWidth;
                    this.context.strokeStyle = this.config.borderColor;
                    this.context.stroke();
                }
                if (this.config.isShowBorder && !this.config.isSign) {
                    //画里面的框
                    this.context.moveTo(0, 0);
                    this.context.lineTo(this.config.canvasWidth, this.config.canvasHeight);
                    this.context.lineTo(this.config.canvasWidth, this.config.canvasHeight / 2);
                    this.context.lineTo(this.config.canvasWidth, this.config.canvasHeight / 2);
                    this.context.lineTo(0, this.config.canvasHeight / 2);
                    this.context.lineTo(0, this.config.canvasHeight);
                    this.context.lineTo(this.config.canvasWidth, 0);
                    this.context.lineTo(this.config.canvasWidth / 2, 0);
                    this.context.lineTo(this.config.canvasWidth / 2, this.config.canvasHeight);
                    this.context.stroke();
                }
                this.$emit('confirm', null);
                this.context.restore();
            },
            /**
             *  保存图片 格式base64
             */
            saveAsImg() {
                const image = new Image();
                image.src = this.canvas.toDataURL("image/png");
                this.$emit('confirm',image.src);
                return image.src;
            },
            /**
             * 初始化画板
             */
            canvasInit () {
                this.canvas.width = this.config.canvasWidth;
                this.canvas.height = this.config.canvasHeight;
                this.config.emptyCanvas = this.canvas.toDataURL("image/png");
                this.bindEvent();
            },
            /**
             * 绑定事件
             */
            bindEvent () {
                //鼠标按下 => 下笔
                this.canvas.addEventListener('mousedown', (e) => {
                    e && e.preventDefault() && e.stopPropagation();
                    this.writeBegin({ x: e.offsetX || e.clientX, y: e.offsetY || e.clientY });
                });
                //书写过程 => 下笔书写
                this.canvas.addEventListener('mousemove', (e) => {
                    e && e.preventDefault() && e.stopPropagation();
                    this.config.isWrite && this.writing({ x: e.offsetX, y: e.offsetY });
                });
                //鼠标松开 => 提笔
                this.canvas.addEventListener('mouseup', (e) => {
                    e && e.preventDefault() && e.stopPropagation();
                    this.writeEnd({ x: e.offsetX, y: e.offsetY });
                });
                //离开书写区域 => 提笔离开
                this.canvas.addEventListener('mouseleave', (e) => {
                    e && e.preventDefault() && e.stopPropagation();
                    this.writeEnd({ x: e.offsetX, y: e.offsetY });
                });
                /* ==========================移动端兼容=Start================================ */
                //手指按下 => 下笔
                this.canvas.addEventListener('touchstart', (e) => {
                    e && e.preventDefault() && e.stopPropagation();
                    const touch = e.targetTouches[0];
                    // const getBCR = touch.target.getBoundingClientRect();
                    const offsetLeft = this.offset(touch.target,'left');
                    const offsetTop = this.offset(touch.target,'top');
                    // const offsetLeft =  touch.target.offsetLeft;
                    // const offsetTop = touch.target.offsetTop;
                    let x = touch.pageX ? touch.pageX - offsetLeft : touch.clientX;
                    let y = touch.pageY ? touch.pageY - offsetTop : touch.clientY;
                    y = touch.pageY - $(e.target).offset().top

                    this.writeBegin({ x, y});
                });
                //手指移动 => 下笔书写
                this.canvas.addEventListener('touchmove', (e) => {
                    e && e.preventDefault() && e.stopPropagation();
                    const touch = e.targetTouches[0];
                    // console.log(touch)
                    const offsetLeft = this.offset(touch.target,'left');
                    const offsetTop = this.offset(touch.target,'top');
                    // const offsetLeft = touch.target.offsetLeft;
                    // const offsetTop = touch.target.offsetTop;
                    let x = touch.pageX ? touch.pageX - offsetLeft : touch.clientX;
                    let y = touch.pageY ? touch.pageY - offsetTop : touch.clientY;
                    y = touch.pageY - $(e.target).offset().top
                    // console.log(e.target, $(e.target).position(), $(e.target).offset())
                    this.config.isWrite && this.writing({ x, y });
                });
                //手指移动结束 => 提笔离开
                this.canvas.addEventListener('touchend', (e) => {
                    e && e.preventDefault() && e.stopPropagation();
                    const tcs = e.targetTouches;
                    const ccs = e.changedTouches;
                    const touch = tcs && tcs.length && tcs[0] || ccs && ccs.length && ccs[0];
                    var offsetLeft = this.offset(touch.target,'left');
                    var offsetTop = this.offset(touch.target,'top');
                    // offsetLeft = 0
                    // offsetTop = 0
                    // console.log(e)
                    // const offsetLeft = touch.target.offsetLeft;
                    // const offsetTop = touch.target.offsetTop;
                    let x = touch.pageX ? touch.pageX - offsetLeft : touch.clientX;
                    let y = touch.pageY ? touch.pageY - offsetTop : touch.clientY;
                    y = touch.pageY - $(e.target).offset().top
                    this.writeEnd({ x, y });
                });
                /* ==========================移动端兼容=End================================ */
            },
            /**
             * 下载二维码到本地
             */
            downloadSignImg(name) {
                const c = document.getElementById(this.domId);
                const dataURL = c.toDataURL('image/png');
                this.saveFile(dataURL, name ? `${name}.${this.config.imgType}` : `${Date.parse(new Date())}.${this.config.imgType}`);
            },
            /**
             * 保存文件
             */
            saveFile(data, filename) {
                const saveLink = document.createElementNS('http://www.w3.org/1999/xhtml', 'a');
                saveLink.href = data;
                saveLink.download = filename;
                const event = document.createEvent('MouseEvents');
                event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
                saveLink.dispatchEvent(event);
            },
            /**
             * 获取dom对象的偏移量 可以获取解决position定位的问题
             */
            offset(obj, direction) {
                //将top,left首字母大写,并拼接成offsetTop,offsetLeft
                const offsetDir = 'offset'+ direction[0].toUpperCase()+direction.substring(1);
                let realNum = obj[offsetDir];
                let positionParent = obj.offsetParent;  //获取上一级定位元素对象
                while(positionParent != null){
                    realNum += positionParent[offsetDir];
                    positionParent = positionParent.offsetParent;
                }
                return realNum;
            }
        }
    };
</script>
